package com.dk.hotel.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.db.PageResult;
import com.alibaba.fastjson.JSON;
import com.dk.hotel.mapper.HotelMapper;
import com.dk.hotel.pojo.Hotel;
import com.dk.hotel.pojo.HotelDoc;
import com.dk.hotel.pojo.PageList;
import com.dk.hotel.pojo.RequestParams;
import com.dk.hotel.service.IHotelService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.apache.lucene.index.Terms;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;

@Service
public class HotelServiceImpl extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {

    @Autowired
    private HotelMapper hotelMapper;

    @Autowired
    private RestHighLevelClient client;

    @Override
    public PageList<HotelDoc> search(RequestParams params) {
        String key = params.getKey();

        SearchRequest request = new SearchRequest("hotel");

        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();

        boolean aNull = Objects.isNull(key);
        boolean empty = StrUtil.isEmpty(key);
        if ((aNull || empty)) {//参数=用户输入的词语    如果不为空就去查询   为空就展示所有数据  all:设置的一个组合字段
            boolQueryBuilder.must(QueryBuilders.matchAllQuery());
        } else {
            boolQueryBuilder.must(QueryBuilders.matchQuery("all", key));
        }// TODO: 2024/6/14  2024年6月14日10:04:22


        //city
        String city = params.getCity();
        if (Objects.nonNull(city) && StrUtil.isNotEmpty(city)) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("city", city));
        }

        //brand
        String brand = params.getBrand();
        if (Objects.nonNull(brand) && StrUtil.isNotEmpty(brand)) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("brand", brand));
        }

        //level
        String starName = params.getStarName();
        if (Objects.nonNull(starName) && StrUtil.isNotEmpty(starName)) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("starName", starName));
        }

        //price
        Integer maxPrice = params.getMaxPrice();
        Integer minPrice = params.getMinPrice();
        if (Objects.nonNull(maxPrice) && Objects.nonNull(minPrice)) {
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(minPrice).lte(maxPrice));
        }// TODO: 2024/6/14  2024年6月14日10:16:34

        //距离排序
        // FIXME: 2024/6/14 不进方法
        String location = params.getLocation();
        if (Objects.nonNull(location) && StrUtil.isNotEmpty(location)) {
            request.source().sort(SortBuilders
                    .geoDistanceSort("location", new GeoPoint())
                    .order(SortOrder.ASC)
                    .unit(DistanceUnit.KILOMETERS));
        }


        //发请求
        try {
            request.source().query(boolQueryBuilder);
            SearchResponse search = client.search(request, RequestOptions.DEFAULT);
            return handleResponse(search);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    // 结果解析
    private PageList<HotelDoc> handleResponse(SearchResponse response) {
        SearchHits hits = response.getHits();

        long total = hits.getTotalHits().value;

        System.out.println("共搜索到:" + total + "条数据!");

        SearchHit[] searchHits = hits.getHits();

        List<HotelDoc> list = new ArrayList<>();
        for (SearchHit searchHit : searchHits) {
            String sourceAsString = searchHit.getSourceAsString();
            HotelDoc hotelDoc = JSON.parseObject(sourceAsString, HotelDoc.class);

            //获取排序值  距离排序
            Object[] sortValues = searchHit.getSortValues();
            if (sortValues.length > 0) {
                Object sortValue = sortValues[0];
                hotelDoc.setDistance(sortValue);
            }

            //放进集合
            list.add(hotelDoc);
        }
        return new PageList<>(total, list);
    }

    //聚合
//    @Override
//    public Map<String, List<String>> getFilters(RequestParams params) {
//        try {
//            // 1.准备Request
//            SearchRequest request = new SearchRequest("hotel");
//            // 2.准备DSL
//            // 2.1.query
//            getbuildBasicQuery(params, request);
//
//            buildAggregation(request);
//            Map<String,List<String>> map =new HashMap<>();
//            SearchResponse search = client.search(request, RequestOptions.DEFAULT);
//
//            List<String> aggByName = getAggByName(search);
//            return map;
//
//
//            // 2.2.设置size
//            request.source().size(0);
//            // 2.3.聚合
//            buildAggregation(request);
//            // 3.发出请求
//            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//            // 4.解析结果
//            Map<String, List<String>> result = new HashMap<>();
//            Aggregations aggregations = response.getAggregations();
//            // 4.1.根据品牌名称，获取品牌结果
//            List<String> brandList = getAggByName(aggregations, "brandAgg");
//            result.put("brand", brandList);
//            // 4.2.根据品牌名称，获取品牌结果
//            List<String> cityList = getAggByName(aggregations, "cityAgg");
//            result.put("city", cityList);
//            // 4.3.根据品牌名称，获取品牌结果
//            List<String> starList = getAggByName(aggregations, "starAgg");
//            result.put("starName", starList);
//
//            return result;
//        } catch (IOException e) {
//            throw new RuntimeException(e);
//        }
//    }

//    private List<String> getAggByName(SearchResponse search) {
//        return null;
//    }

//    private void getbuildBasicQuery(RequestParams params, SearchRequest request) {
//        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//
//        //搜索
//        String key = params.getKey();
//        if (StrUtil.isNotEmpty(key)) {
//            boolQueryBuilder.must(QueryBuilders.matchQuery("all", key));
//        } else {
//            boolQueryBuilder.must(QueryBuilders.matchAllQuery());
//        }
//    }

//    private void buildAggregation(SearchRequest request) {
//        request.source().aggregation(AggregationBuilders
//                .terms("brandAgg")
//                .field("brand")
//                .size(100)
//        );
//        request.source().aggregation(AggregationBuilders
//                .terms("cityAgg")
//                .field("city")
//                .size(100)
//        );
//        request.source().aggregation(AggregationBuilders
//                .terms("starAgg")
//                .field("starName")
//                .size(100)
//        );
//    }

//    private List<String> getAggByName(Aggregations aggregations, String aggName) {
//        // 4.1.根据聚合名称获取聚合结果
//        Terms brandTerms = aggregations.get(aggName);
//        // 4.2.获取buckets
//        List<? extends Terms.Bucket> buckets = brandTerms.getBuckets();
//        // 4.3.遍历
//        List<String> brandList = new ArrayList<>();
//        for (Terms.Bucket bucket : buckets) {
//            // 4.4.获取key
//            String key = bucket.getKeyAsString();
//            brandList.add(key);
//        }
//        return brandList;
//    }
}
